package cn.dansj.handler.tasks;

import cn.dansj.annotation.MarkAsTask;
import cn.dansj.common.utils.json.DictMap;
import cn.dansj.common.utils.file.FileUtils;
import cn.dansj.common.utils.transfer.ArrayUtils;
import cn.dansj.common.utils.transfer.DateTime;
import cn.dansj.common.utils.transfer.Transformation;
import cn.dansj.common.utils.transfer.Verification;
import com.alibaba.fastjson2.JSONWriter;
import com.xxl.job.enums.TableConstant;
import com.xxl.job.handler.Job;

import java.io.File;
import java.lang.reflect.Modifier;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@MarkAsTask(id = 102)
public class BackupTableData extends Job {
    private static final String userHome = System.getProperty("user.home");
    private static final List<String> rejectTables = ArrayUtils.asList("x_request_log", "xxl_job_log");

    @Override
    public void execute() throws Exception {
        final String basepath = userHome + "/backup/dansj";
        final String path = basepath + "/" + DateTime.getInstance().toString("yyyyMMdd");
        final File file = new File(path);
        if (!file.exists()) file.mkdirs();
        final String xxl_job_path = path + "/table_xxl_job.sql";
        final String base_manage_path = path + "/base_manage.sql";
        final File xxl_job_file = new File(xxl_job_path);
        if (xxl_job_file.exists()) xxl_job_file.delete();
        final File base_manage_file = new File(base_manage_path);
        if (base_manage_file.exists()) base_manage_file.delete();

        final List<String> map = jdbcTemplate.queryForList("show tables").stream().map(e -> e.values().stream().toList().get(0).toString()).collect(Collectors.toList());
        for (String table : map) {
            final Object createTable = jdbcTemplate.queryForMap("show create table " + table).get("create table");
            FileUtils.writeToFile(path + "/" + table + ".sql", Transformation.toString(createTable) + "\n", StandardOpenOption.CREATE);
            logger.info("table: {}, sql file: {}", table, path + "/" + table + ".sql");

            // 获取所有的xxl_job用到的表
            final List<String> xxlJobTable = Arrays.stream(TableConstant.class.getDeclaredFields()) // 获取所有字段
                    .filter(field -> Modifier.isStatic(field.getModifiers())) // 过滤出静态字段
                    .filter(field -> Modifier.isPublic(field.getModifiers())) // 过滤出 public 字段
                    .peek(field -> field.setAccessible(true)) // 设置字段可访问（如果需要）
                    .map(field -> {
                        try {
                            return Transformation.toString(field.get(null)); // 获取静态字段的值
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException("Failed to access field: " + field.getName(), e);
                        }
                    })
                    .toList();

            FileUtils.writeToFile(xxlJobTable.contains(table) ? xxl_job_path : base_manage_path, Transformation.toString(createTable) + ";\n\n", StandardOpenOption.CREATE, StandardOpenOption.APPEND);

            if (rejectTables.contains(table)) continue;
            final List<Map<String, Object>> data = jdbcTemplate.queryForList("select * from " + table);
            if (Verification.checkNotNull(data)) {
                FileUtils.writeToFile(path + "/" + table + ".json", DictMap.toJSONString(data, JSONWriter.Feature.WriteMapNullValue), StandardOpenOption.CREATE);
                logger.info("table: {}, json file: {}", table, path + "/" + table + ".json");
            }
        }

        FileUtils.writeToFile(xxl_job_path, """
                INSERT INTO xxl_job_group(id, app_name, title, address_type, address_list, update_time)
                VALUES (1, 'xxl-job-executor', '默认执行器组', 0, NULL, current_timestamp());
                """, StandardOpenOption.CREATE, StandardOpenOption.APPEND);

        final File menu = new File(basepath);
        for (File child : menu.listFiles()) {
            if (DateTime.isDateTime(child.getName()) && DateTime.getInstance(child.getName()).compareTo(DateTime.getInstance().addDay(-10).trunc()) < 0 && FileUtils.deleteDirectory(child)) {
                logger.info("删除过期备份文件夹：{}", child.getPath());
            }
        }
    }
}
